#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using PHSRAG.Insight21.InsightUtilities;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
using ExpenseInfoConstants = PHSRAG.Insight21.Agreements.AgreementConstants.ExpenseInfoConstants;
using AgreementsConstants = PHSRAG.Insight21.InsightUtilities.Constants.AgreementsConstants;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
#endregion

namespace PHSRAG.Insight21.Agreements
{
	#region Class ExpenseOverview
	/// <summary>
	/// The ExpenseOverview class supports loading of all expense overview information
	/// for the logged in user and the given set of summary search criteria.
	/// </summary>
	public class ExpenseOverview : BO.BusinessObject
	{
		#region Class Variables

        private enum LoadMethodArgs
        {
            SearchCriteria,
            FundNumber,
            SessionID,
            Count
        }

		/// <summary>
		/// The TableNames array MUST declare the names in the exact sequence in which the GetExpenseInfo stored procedure
		/// returns tables within its resultset.
		/// </summary>
		private static readonly string[] TableNames = {
														  ExpenseInfoConstants.FundsPerMonthTableName,
														  AgreementsConstants.CategoryTableName,
														  ExpenseInfoConstants.CategoryTotalTableName,
														  AgreementsConstants.AccountsTableName,
														  ExpenseInfoConstants.AccountTotalTableName,
														  AgreementsConstants.DirectCostsTableName,
														  ExpenseInfoConstants.DirectCostBalanceTableName,
														  AgreementsConstants.IndirectCostsTableName,
														  AgreementsConstants.TotalCostsTableName,
														  AgreementsConstants.RevenueTableName,
														  AgreementsConstants.CashBalanceTableName,
                                                          ExpenseInfoConstants.FooterTotalsTableName 
                                                          
													  };
		/// <summary>
		/// The AccountTableNames array MUST declare the names in the exact sequence in which the GetExpenseInfo2 stored procedure
		/// returns tables within its resultset.
		/// </summary>
		private static readonly string[] AccountTableNames = {
														  AgreementsConstants.AccountsTableName,
														  ExpenseInfoConstants.AccountTotalTableName
                                                        
													  };
		#endregion

		#region Constructor
		/// <summary>
		/// Parameterized constructor, Initialize the base class with the active cache policy
		/// </summary>
		/// <param name="cachePolicy">Active cache policy</param>
		public ExpenseOverview(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		}
		#endregion

		#region Public properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return GenerateKey.MakeKey("ExpenseOverview_F1EB0573-FE58-4044-B6D5-0B2A72D0FD0F",GenerateKey.Agreement); } }
		#endregion

		#region Businessobject methods
		/// <summary>
		/// Cache the current instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(CacheKey, this);
		}

        /// <summary>
		/// Remove the current instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(CacheKey);
		}

        private bool IsDate(string sdate)
        {
            try
            {
                DateTime.Parse(sdate);
                return true;
            }
            catch
            {
            }
            return false;
        }

		/// <summary>
		/// Load the current instance with Expense overview data for the current user.
		/// </summary>
		/// <param name="connectionString"> Database connection string</param>
		/// <param name="args">Is expected to contain the SearchCriteria instance
		/// The search critera instance is expeceted to contain atleast the domain user id</param>
		public override void Load(string connectionString, params object[] args)
		{
			if (args.Length != 2)
				throw new Exception("ExceptionOverview load requires SearchCriteria to be specified");

			SearchCriteria searchCriteria = (SearchCriteria)args[0];
			string sessionID = (string) args[1];
			System.Diagnostics.Trace.WriteLine(string.Format("{0}: ExpenseOverview: SC {1}", DateTime.Now, searchCriteria));

            if ((searchCriteria[Constants.ProjectStartDateKey] != null) && !IsDate(searchCriteria[Constants.ProjectStartDateKey]))
                throw new Exception("Project Start Date contains an invalid date.");

            if ((searchCriteria[Constants.ProjectEndDateKey] != null) && !IsDate(searchCriteria[Constants.ProjectEndDateKey]))
                throw new Exception("Project End Date contains an invalid date.");
					
            if ((searchCriteria[Constants.BudgetStartDateKey] != null) && !IsDate(searchCriteria[Constants.BudgetStartDateKey]))
                throw new Exception("Budget Start Date contains an invalid date.");

            if ((searchCriteria[Constants.BudgetEndDateKey] != null) && !IsDate(searchCriteria[Constants.BudgetEndDateKey]))
                throw new Exception("Budget End Date contains an invalid date.");

            if ((searchCriteria[Constants.ExpenseFromDateKey] != null) && !IsDate(searchCriteria[Constants.ExpenseFromDateKey]))
                throw new Exception("Month From Date contains an invalid date.");

            if ((searchCriteria[Constants.ExpenseToDateKey] != null) && !IsDate(searchCriteria[Constants.ExpenseToDateKey]))
                throw new Exception("Month To Date contains an invalid date.");

            if ((searchCriteria[Constants.ProjectStartDateKey] != null) && (searchCriteria[Constants.ProjectEndDateKey] != null))
                if (DateTime.Compare(DateTime.Parse(searchCriteria[Constants.ProjectStartDateKey]),DateTime.Parse(searchCriteria[Constants.ProjectEndDateKey])) > 0)
                    throw new Exception("Project Start Date cannot be after Project End Date.");

            if ((searchCriteria[Constants.BudgetStartDateKey] != null) && (searchCriteria[Constants.BudgetEndDateKey] != null))
                if (DateTime.Compare(DateTime.Parse(searchCriteria[Constants.BudgetStartDateKey]),DateTime.Parse(searchCriteria[Constants.BudgetEndDateKey])) > 0)
                    throw new Exception("Budget Start Date cannot be after Budget End Date.");

            if ((searchCriteria[Constants.ExpenseFromDateKey] != null) && (searchCriteria[Constants.ExpenseToDateKey] != null))
                if (DateTime.Compare(DateTime.Parse(searchCriteria[Constants.ExpenseFromDateKey]),DateTime.Parse(searchCriteria[Constants.ExpenseToDateKey])) > 0)
                    throw new Exception("Month From Date cannot be after Month To Date.");

			DataContainer = DataAccess.GetDataSet(connectionString, "GetExpenseInfo1",
				DataAccess.BuildSqlParameterArray(
				"@SessionID", SqlDbType.VarChar, sessionID,
				"@domainUserId", SqlDbType.Int, searchCriteria[Constants.DomainUserIDKey],
				"@includeProgramProjects", SqlDbType.Bit, searchCriteria[Constants.IncludeProgramProjectsKey],
				"@fundNumber", SqlDbType.VarChar, searchCriteria[Constants.FundIDKey],
				"@folderNumber", SqlDbType.VarChar, searchCriteria[Constants.FolderNumberKey],
				"@bicsNumber", SqlDbType.VarChar, searchCriteria[Constants.BicsNumberKey],
				"@walkerNumber", SqlDbType.VarChar, searchCriteria[Constants.WalkerNumberKey],
				"@sponsorNumber", SqlDbType.VarChar, searchCriteria[Constants.SponsorNumberKey],
				"@sponsorName", SqlDbType.VarChar, searchCriteria[Constants.SponsorNameKey],
				"@sponsorTypeId", SqlDbType.Int, searchCriteria[Constants.SponsorTypeIDKey],
				"@agreementTypeId", SqlDbType.Int, searchCriteria[Constants.AgreementTypeIDKey],
				"@activityCode", SqlDbType.VarChar, searchCriteria[Constants.ActivityCodeKey],
				"@locationId", SqlDbType.Int, searchCriteria[Constants.LocationIDKey],
				"@budgetStartDate", SqlDbType.DateTime, searchCriteria[Constants.BudgetStartDateKey],
				"@budgetEndDate", SqlDbType.DateTime, searchCriteria[Constants.BudgetEndDateKey],
				"@projectStartDate", SqlDbType.DateTime, searchCriteria[Constants.ProjectStartDateKey],
				"@projectEndDate", SqlDbType.DateTime, searchCriteria[Constants.ProjectEndDateKey],
				"@piId", SqlDbType.Int, searchCriteria[Constants.PIIDKey],
				"@chiefCodeList", SqlDbType.VarChar, searchCriteria.COSIds,
				"@sponsorGroupTypeId", SqlDbType.Int, searchCriteria[Constants.ViewingOptionKey],
				"@budgetEndingDays", SqlDbType.Int, searchCriteria[Constants.DaysBudgetEndingKey],
				"@projectEndingDays", SqlDbType.Int, searchCriteria[Constants.DaysProjectEndingKey],
				"@fundCreatedDays", SqlDbType.Int, searchCriteria[Constants.DaysFundCreatedKey],
				"@lowBalance", SqlDbType.Decimal, searchCriteria[Constants.BalanceLessThanKey],
				"@highBalance", SqlDbType.Decimal, searchCriteria[Constants.BalanceGreaterThanKey],
				"@agreementStatusTypeList", SqlDbType.VarChar, searchCriteria[Constants.AgreementStatusIDKey],
				"@fundStatusTypeId", SqlDbType.Int, searchCriteria[Constants.FundStatusIDKey],
				"@categoryId", SqlDbType.Int, searchCriteria[Constants.CategoryIDKey],
				"@accountNumber",SqlDbType.VarChar,searchCriteria[Constants.AccountNumberKey],
				"@expenseDateFrom", SqlDbType.DateTime, searchCriteria[Constants.ExpenseFromDateKey],
				"@expenseDateTo", SqlDbType.DateTime, searchCriteria[Constants.ExpenseToDateKey],
				"@incomingFundNumber", SqlDbType.VarChar, null,
				"@monthEndingDate", SqlDbType.DateTime, null
				));

			DataSet expenseOverviewData = DataContainer;
            if (expenseOverviewData.Tables.Count != TableNames.Length)
                throw new Exception("Failed to load expense overview information.");

        	for (int i = 0, count = TableNames.Length; i < count; ++i)
				expenseOverviewData.Tables[i].TableName = TableNames[i];

           // expenseOverviewData.Tables[13].TableName = AgreementsConstants.ProjectHeader;
            // we're no longer using the direct cost balance table, so take it out for now
            expenseOverviewData.Tables.Remove(ExpenseInfoConstants.DirectCostBalanceTableName);
		}

		/// <summary>
		/// Load the current instance with category account data for the current user and category clicked.
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expected to contain the SearchCriteria instance
		/// The search critera instance is expeceted to contain atleast the domain user id</param>
		public void LoadCategoryAccounts(string connectionString, params object[] args)
		{
			if (args.Length != 3)
				throw new Exception("ExceptionOverview load requires SearchCriteria to be specified");

			SearchCriteria searchCriteria = (SearchCriteria) args[0];
			string sessionID = (string) args[1];
			int categoryID = (int) args[2];

			System.Diagnostics.Trace.WriteLine(string.Format("{0}: ExpenseOverview: SC {1}", DateTime.Now, searchCriteria));

			if ((searchCriteria[Constants.ExpenseFromDateKey] != null) && !IsDate(searchCriteria[Constants.ExpenseFromDateKey]))
				throw new Exception("Month From Date contains an invalid date.");

			if ((searchCriteria[Constants.ExpenseToDateKey] != null) && !IsDate(searchCriteria[Constants.ExpenseToDateKey]))
				throw new Exception("Month To Date contains an invalid date.");

			if ((searchCriteria[Constants.ExpenseFromDateKey] != null) && (searchCriteria[Constants.ExpenseToDateKey] != null))
				if (DateTime.Compare(DateTime.Parse(searchCriteria[Constants.ExpenseFromDateKey]),DateTime.Parse(searchCriteria[Constants.ExpenseToDateKey])) > 0)
					throw new Exception("Month From Date cannot be after Month To Date.");

			DataSet accountTables = DataAccess.GetDataSet(connectionString, "GetExpenseInfo2",
				DataAccess.BuildSqlParameterArray(
				"@SessionID", SqlDbType.VarChar, sessionID,
				"@domainUserId", SqlDbType.Int, searchCriteria[Constants.DomainUserIDKey],
				"@categoryId", SqlDbType.Int, categoryID,
				"@accountNumber",SqlDbType.VarChar,searchCriteria[Constants.AccountNumberKey],
				"@expenseDateFrom", SqlDbType.DateTime, searchCriteria[Constants.ExpenseFromDateKey],
				"@expenseDateTo", SqlDbType.DateTime, searchCriteria[Constants.ExpenseToDateKey]
				));

         
			if (accountTables.Tables.Count != AccountTableNames.Length)
				throw new Exception("Failed to load account information.");

			for (int i = 0, count = AccountTableNames.Length; i < count; ++i)
				accountTables.Tables[i].TableName = AccountTableNames[i];
            
            DataSet expenseOverviewData = DataContainer;            

			if (expenseOverviewData.Tables.Contains(AgreementsConstants.AccountsTableName) )
			{
				DataTable accounts = expenseOverviewData.Tables[AgreementsConstants.AccountsTableName];
				//if (categoryID==0) 
                    accounts.Clear();
				foreach (DataRow dataRow in accountTables.Tables[AgreementsConstants.AccountsTableName].Rows)
					accounts.ImportRow(dataRow);

				DataTable accountTotals = expenseOverviewData.Tables[ExpenseInfoConstants.AccountTotalTableName];
				//if (categoryID==0) 
                    accountTotals.Clear();
				foreach (DataRow dataRow in accountTables.Tables[ExpenseInfoConstants.AccountTotalTableName].Rows)
					accountTotals.ImportRow(dataRow);
			}
			else 
			{
				expenseOverviewData.Tables.Add(accountTables.Tables[AgreementsConstants.AccountsTableName]);
				expenseOverviewData.Tables.Add(accountTables.Tables[ExpenseInfoConstants.AccountTotalTableName]);
			}

		}

		#endregion
	}
	#endregion
}